/*
 * Copyright (C) 2012 POAS.VSTU
 */

package ui;

import model.Card;

import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Insets; 
import java.awt.Dimension; 
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;


/**
 * Класс карта.
 * Описывает карту, как физический объект игрового процесса.
 * Управляет поворотами карты на плоскости и в пространстве.
 * Управляет перемещением карты по игровому полю.
 */
public class UICard implements RotatableLabel{   
    /** Виджет (метка), которым реализуется представление карты */
    private UILabel     mLabel;
    
    /** Панель игры */
    private UIGamePanel mPanel;
    
    /** Модель карты, с которой связано данное представление */
    private Card        mCardModel;
    
    /** Отображается лицевой стороной */
    private boolean     mFaceUp;

    /** Изображение карты */
    private ImageIcon   mFaceUpIcon;
    
    /** Изображение рубашки */
    private ImageIcon   mFaceDownIcon;
    
    // Это имя папки внутри папки Images, которая содержит определённый набор карт.
    // Выбор папки с набором карт должен осуществляться из настроек.
    public String dir = "Deck";
    
    /**
     * Конструктор.
     * @param card модель карты.
     * @param panel игровая панель, куда добавляется карта при создании.
     */
    public UICard(Card card, UIGamePanel panel) {
        mCardModel = card;
        mFaceUp = true;
        mLabel = new UILabel();
        mPanel = panel;
        
        // Указываем относительный путь к папке images
        String directory = "/images/";
        
        // Прибавляем к нему имя папки с картами в папке images
        String iconFile = directory;
        iconFile += dir;
        iconFile += "/";
        
        // Прибавляем к нему масть и наминал карты для её изображения
        String iconFile1 = iconFile+card.getSuit();
        iconFile1 += "_";
        iconFile1 += card.getFace();
        iconFile1 += ".jpg";
        
        // Прибавляем к нему Back для рубашки
        String iconFile2 = iconFile+"BACK.jpg";
        
        // Инициализируем поля соответствующими карте изображениями
        mFaceUpIcon = new ImageIcon(getClass().getResource(iconFile1));
        mFaceDownIcon = new ImageIcon(getClass().getResource(iconFile2));
                
        mLabel.setIcon(mFaceUpIcon);
        int f = mLabel.getWidth();
        
        // Задаём ширину и высоту карты
        setScale(73);
        
        // Добавляем карту на панель
        mPanel.add(mLabel);
      
        Insets insets = mPanel.getInsets();
        Dimension size = mLabel.getPreferredSize();
        mLabel.setBounds(insets.left, insets.top, size.width, size.height);
        
        mLabel.setOrientation(Orientation.NORMAL);
    }
    
    /** Модель, связанная с представлением */
    public Card getModel() {
        return mCardModel;
    }
    
    /** Связать с представлением новую карту */
    public void setModel(Card card) {
        mCardModel = card;
    }
    
    /** Повернуть карту лицом вверх. */
    public void turnFaceUp() {
        mFaceUp = true;
        mLabel.setIcon(mFaceUpIcon);
    }
    
    /** Повернуть карту лицом вниз. */
    public void turnFaceDown() {
        mFaceUp = false;
        mLabel.setIcon(mFaceDownIcon);  
    }
    
    /** Карта отображается лицевой стороной */
    public boolean isFaceUp() {
        return mFaceUp;
    }

    /** Карта отображается рубашкой */
    public boolean isFaceDown() {
        return !mFaceUp;
    }
    
    /** Ориентация карты */
    @Override
    public Orientation getOrientation() {
        return mLabel.orientation;
    }
    
    /** Задать ориентацию карты */
    @Override
    public void setOrientation(Orientation orientation) {
         mLabel.setOrientation(orientation);
    }
    
    /** 
     * Повернуть карту.
     * @param steps кол-во поворотов в шагах. Один шаг соответствует повороту на
     * 90 градусов. Положительные значения соответствуют повороту по часовой стрелке,
     * отрицательные - против часовой стрелки.
     */
    public void  rotate(int steps) { 
        int nowPos = getOrientation().ordinal();
        for(int i = 0; i < Math.abs(steps); i++) {
            if(steps > 0)
                    nowPos++;
            if(steps < 0)
                    nowPos--;
        
            if(nowPos == 4)
                nowPos = 0;
            if(nowPos == -1)
                nowPos = 3;
        }
        
        setOrientation(Orientation.values()[nowPos]);
    }
    
    /** Изменить размеры карты. 
     *  @param width ширина карты 
     *  (высота вычисляется автоматически исходя из изначального соотношения ширины и высоты изображения)
     */
    public void setScale(int width) {
        ImageIcon icon;
        double k = (double) mFaceUpIcon.getIconHeight() / (double) mFaceUpIcon.getIconWidth();
        
        icon = new ImageIcon(mFaceUpIcon.getImage().getScaledInstance(width, (int) (k * width), mFaceUpIcon.getImage().SCALE_DEFAULT));
        mFaceUpIcon = icon;
     
        icon = new ImageIcon(mFaceDownIcon.getImage().getScaledInstance(width, (int) (k * width), mFaceDownIcon.getImage().SCALE_DEFAULT));
        mFaceDownIcon = icon;
        
        if(mFaceUp)
            mLabel.setIcon(mFaceUpIcon);
        else
            mLabel.setIcon(mFaceDownIcon);
    }
    
    /** Позиция */
    public Point getLocation() {
        return mLabel.getLocation();
    }

    /** Задать позицию */
    public void setLocation(Point p) {
        mLabel.setLocation(p);
    }
    
    /** Задать позицию */
    public void setLocation(int x, int y) {
        mLabel.setLocation(x, y);
    }
    
    /** Ширина метки карты */
    public int getWidthLabel() {
        return mLabel.getWidth();
    }
    
    /** Высота метки карты */
    public int getHeightLabel() {
        return mLabel.getHeight();
    }
    
    /** Ширина карты */
    public int getWidth() {
        if(mLabel.orientation == Orientation.ROTATED_ANTI_CLOCKWISE || mLabel.orientation == Orientation.ROTATED_CLOCKWISE)
            return mLabel.getHeight();
        else
            return mLabel.getWidth();
    }
    
    /** Высота карты */
    public int getHeight() {
        if(mLabel.orientation == Orientation.ROTATED_ANTI_CLOCKWISE || mLabel.orientation == Orientation.ROTATED_CLOCKWISE)
            return mLabel.getWidth();
        else
            return mLabel.getHeight();
    }
    
    /** Приведение к строке */
    @Override
    public String toString() {
        return mCardModel.toString();
    }
    

    

    
    /**
     * Aбсолютная z-координата на панели.
     * @return индекс слоя на панели (индекс самого верхнего слоя = 0)
     */
    public int getZOrder() {
        return mPanel.getComponentZOrder(mLabel);
    }	

    /**
     * Задать абсолютную z-координату на панели.
     * @param index индекс слоя на панели (индекс самого верхнего слоя = 0)
     */
    public void setZOrder(int index) {
	mPanel.setComponentZOrder(mLabel, index);
    }    
    
    
    public JLabel getLabel() {
        return mLabel;
    }
    
    
    
    
       /**
     * Перемещает карту в заданную точку с анимацией.
     * @param xx координата x
     * @param yy координата y
     */
    public void actionMoveTo(Point toPoint, MovementSpeed speed, int delaySteps) {
        mPanel.addMovement(getActionMove(toPoint, speed, delaySteps));
    }
    
    public void actionTurnFaceUp(int delaySteps) {
        mPanel.addMovement(getActionTurnFaceUp(delaySteps));
    }
    
    public void actionTurnFaceDown(int delaySteps) {
        mPanel.addMovement(getActionTurnFaceDown(delaySteps));
    }
    
    public void actionSetOrientation(Orientation orientation, int delaySteps) {
        mPanel.addMovement(getActionRotate(orientation, delaySteps));
    }
    
    public void actionSetZOrder(int zOrder, int delaySteps) {
        mPanel.addMovement(getActionSetZOrder(zOrder, delaySteps));
    }
    
    private Action getActionMove(Point toPoint, MovementSpeed speed, int delaySteps) {
        return new Action(mLabel, toPoint.x, toPoint.y, speed, delaySteps);
    }
    
    
    private Action getActionRotate(Orientation orientation, int delaySteps) {
        Action action = new Action(mLabel, delaySteps);
        action.setOrientation(this, orientation);
        return action;
    }
    
    
    private Action getActionTurnFaceUp(int delaySteps) {
        Action action = new Action(mLabel, delaySteps);
        action.setTurnFaceUp(this);
        return action;
    }
    
    private Action getActionTurnFaceDown(int delaySteps) {
        Action action = new Action(mLabel, delaySteps);
        action.setTurnFaceDown(this);
        return action;
    }
    
    private Action getActionSetZOrder(int zIndex, int delaySteps) {
        Action action = new Action(mLabel, delaySteps);
        action.setZOrder(this, zIndex);
        return action;
    }  
}